package com.wenwen.social.domain.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.wenwen.social.common.exception.ServiceException;
import com.wenwen.social.constant.UserConstant;
import com.wenwen.social.domain.model.User;
import com.wenwen.social.domain.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.wenwen.social.constant.errorcode.CommonErrorConstant.*;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void createUser(User user) {
        try {
            Map<String, Object> userMap = BeanUtil.beanToMap(user);
            HashOperations operations = redisTemplate.opsForHash();
            operations.putAll(getUserKey(user.getId()), userMap);
        } catch (Exception e) {
            log.error("user save redis error.{}", JSONObject.toJSON(user), e);
            throw new ServiceException(SYSTEM_ERROR_CODE,SYSTEM_ERROR_MSG);
        }
    }

    @Override
    public User getUser(Long userId) {
        HashOperations operations = redisTemplate.opsForHash();

        Map userMap = operations.entries(getUserKey(userId));

        if (userMap != null) {
            try {
               return cn.hutool.core.bean.BeanUtil.mapToBean(userMap, User.class,true);
            } catch (Exception e) {
                log.error("user get from redis error.userId:{}", userId, e);
                throw new ServiceException(SYSTEM_ERROR_CODE,SYSTEM_ERROR_MSG);
            }
        }
        return null;
    }

    @Override
    public List<User> getUsers(List<Long> userIds) {

        List<Object> userList = redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
                for (Long userId : userIds) {
                    redisConnection.hGetAll(getUserKey(userId).getBytes());
                }
                return null;
            }
        });

        if (userList == null || userList.isEmpty()) {
            return new ArrayList<>();
        }

        List<User> resultList = userList.stream().map(new Function<Object, User>() {
            @Override
            public User apply(Object userMap) {
                return BeanUtil.mapToBean((Map)userMap, User.class, true);
            }
        }).collect(Collectors.toList());

        return resultList;
    }

    @Override
    public Map<Long, User> getUsersMap(List<Long> userIds) {

        List<User> userList=getUsers(userIds);

        if (userList.isEmpty()){
            return new HashMap<Long, User>();
        }

        return userList.stream().collect(Collectors.toMap(User::getId,user->user));
    }

    @Override
    public void updateUser(User user) {
        try {
            Map<String, Object> userMap = BeanUtil.beanToMap(user);
            HashOperations operations = redisTemplate.opsForHash();
            operations.putAll(getUserKey(user.getId()), userMap);
        } catch (Exception e) {
            log.error("user update redis error.{}", JSONObject.toJSON(user), e);
            throw new ServiceException(SYSTEM_ERROR_CODE,SYSTEM_ERROR_MSG);
        }
    }

    private String getUserKey(Long userId) {
        return UserConstant.USER_PRE + userId;
    }
}
